<?php
declare(strict_types=1);
namespace SixShop\WechatPay\Entity;


use SixShop\Core\Entity\BaseEntity;
use SixShop\WechatPay\Enum\TransferBillStatusEnum;
use SixShop\WechatPay\Event\TransferBillFailedEvent;
use SixShop\WechatPay\Event\TransferSceneReportEvent;
use SixShop\WechatPay\Trait\ApiTrait;
use think\db\Query;
use think\facade\Db;
use think\facade\Event;
use think\Model;
use think\Paginator;
use function SixShop\Core\throw_logic_exception;

/**
 * @mixin \SixShop\WechatPay\Model\WechatpayTransferBillModel
 */
class WechatpayTransferBillEntity extends BaseEntity
{
    use  ApiTrait;
    public function getTransferBillList(array $params, array $page): Paginator
    {
        $query = $this->withSearch(['state', 'out_bill_no'], $params);
        return $query->with(['user' => function (Query $query) {
            $query->field(['id', 'avatar','username', 'mobile','nickname']);
        }])->append(['state_text'])->order('id', 'desc')->paginate($page);
    }

    public function getTransferBillStats(array $params): array
    {
        return $this->field('state, count(*) as count, sum(transfer_amount + fee) as amount')
            ->group('state')
            ->select()
            ->toArray();
    }

    public function refreshTransferBill(int $id): self
    {
        $transferBill = $this->findOrEmpty($id);
        if ($transferBill->isEmpty()) {
            throw_logic_exception('提现单不存在');
        }
        $result = match ($transferBill->state) {
            TransferBillStatusEnum::SUCCESS,
            TransferBillStatusEnum::FAIL,
            TransferBillStatusEnum::CANCELLED => throw_logic_exception('提现单已是最终状态不允许刷新'),
            TransferBillStatusEnum::APPLYING => throw_logic_exception('提现单申请中不允许刷新'),
            default => $this->queryTransferBill($transferBill->out_bill_no),
        };
        $transferBill->state = TransferBillStatusEnum::from($result->state);
        $transferBill->fail_reason = match ($transferBill->state) {
            TransferBillStatusEnum::FAIL,
            TransferBillStatusEnum::CANCELLED => $result->fail_reason,
            default => '',
        };
        Db::transaction(function () use ($transferBill) {
            if ($transferBill->state === TransferBillStatusEnum::FAIL
                || $transferBill->state === TransferBillStatusEnum::CANCELLED) {
                Event::trigger(new TransferBillFailedEvent($transferBill->id));
            }
            $transferBill->save();
        });
        return $transferBill;
    }

    public function approveTransferBill(int $id): self
    {
        $transferBill = $this->findOrEmpty($id);
        if ($transferBill->isEmpty()) {
            throw new Exception('提现单不存在');
        }
        if ($transferBill->state !== TransferBillStatusEnum::APPLYING) {
            throw_logic_exception('非法操作');
        }
        // 转账场景报备信息
        $event = new TransferSceneReportEvent($transferBill);
        Event::trigger($event);
        $result = $this->transferBill(
            outBillNo: $transferBill->out_bill_no,
            transferSceneId:$event->getTransferSceneId(),
            openid: $transferBill->openid,
            transferAmount: $transferBill->transfer_amount,
            transferRemark: $transferBill->transfer_remark,
            transferSceneReportInfos: $event->getTransferSceneReportInfos(),
            userName: $transferBill->user_name,
            userRecvPerception: $event->getUserRecvPerception(),
        );
        $transferBill->transfer_scene_id = $event->getTransferSceneId();
        $transferBill->user_recv_perception = $event->getUserRecvPerception();
        $transferBill->transfer_bill_no = $result->transfer_bill_no;
        $datetime = new \DateTime($result->create_time);
        $transferBill->accept_time = $datetime->format('Y-m-d H:i:s');
        $transferBill->state = $result->state;
        $transferBill->package_info = $result->package_info;
        $transferBill->save();
        return $transferBill;
    }

    public function rejectTransferBill(int $id, string $failReason): self
    {
        $transferBill = $this->findOrEmpty($id);
        if ($transferBill->isEmpty()) {
            throw new Exception('提现单不存在');
        }
        if ($transferBill->state !== TransferBillStatusEnum::APPLYING) {
            throw_logic_exception('非法操作');
        }
        $transferBill->state = TransferBillStatusEnum::FAIL;
        $transferBill->fail_reason = $failReason;
        Db::transaction(function () use ($transferBill) {
            $transferBill->save();
            Event::trigger(new TransferBillFailedEvent($transferBill->id));
        });

        return $transferBill;
    }
}